#include "transistor.h"

Transistor::Transistor()
{
    drawNetNames = true;
    routedWithPo = false;
    routed = false;

    gateRect = QRectF(-Rules::getRule("PO.W.1a")/2,
                      0,
                      Rules::getRule("PO.W.1a"),
                      (Rules::getRule("PO.O.1")*2) + (Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1"));

    diffRect = QRectF(-((Rules::getRule("PO.W.1a")/2) + Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1")),
                      Rules::getRule("PO.O.1"),
                      Rules::getRule("PO.W.1a") + (Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1"))*2,
                      (Rules::getRule("CO.E.1")*2) + Rules::getRule("CO.W.1"));

    leftContRect = QRectF(-((Rules::getRule("PO.W.1a")/2) + Rules::getRule("CO.C.1") + Rules::getRule("CO.W.1")),
                          Rules::getRule("PO.O.1") + Rules::getRule("CO.C.1"),
                          Rules::getRule("CO.W.1"),
                          Rules::getRule("CO.W.1"));

    rightContRect = QRectF((Rules::getRule("PO.W.1a")/2) + Rules::getRule("CO.C.1"),
                           Rules::getRule("PO.O.1") + Rules::getRule("CO.C.1"),
                           Rules::getRule("CO.W.1"),
                           Rules::getRule("CO.W.1"));

    this->setFlag(QGraphicsItem::ItemIsMovable);

    routedPos = QPointF(0,0);
}

void Transistor::setTransistorName(QString name)
{
    this->transistorName = name;
}

void Transistor::setSourceNetName(QString name)
{
    this->sourceNetName = name;
}

void Transistor::setGateNetName(QString name)
{
    this->gateNetName = name;
}

void Transistor::setDrainNetName(QString name)
{
    this->drainNetName = name;
}

void Transistor::setBulkNetName(QString name)
{
    this->bulkNetName = name;
}

void Transistor::setTransistorType(QString name)
{
    transistorType = name;
}

void Transistor::setPosIndex(int i)
{
    this->posIndex = i;
}

void Transistor::setW(qreal w)
{
    this->w = w;

    gateRect = QRectF(-Rules::getRule("PO.W.1a")/2,
                      0,
                      Rules::getRule("PO.W.1a"),
                      this->w + (Rules::getRule("PO.O.1")*2));

    diffRect = QRectF(-((Rules::getRule("PO.W.1a")/2) + Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1")),
                      Rules::getRule("PO.O.1"),
                      Rules::getRule("PO.W.1a") + (Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1"))*2,
                      this->w );

}

void Transistor::setL(qreal l)
{
    this->l = l;
}

void Transistor::removeLeftContact()
{
    diffRect.setLeft(-Rules::getRule("PO.C.2") -(Rules::getRule("PO.W.1a")/2));
}

void Transistor::removeRightContact()
{
    diffRect.setRight(Rules::getRule("PO.C.2") +(Rules::getRule("PO.W.1a")/2));
}

QPointF Transistor::getSourceContPos()
{
    if(!this->flipped)
        return this->mapToScene(this->leftContRect.center());

    return this->mapToScene(this->rightContRect.center());
}

QPointF Transistor::getDrainContPos()
{
    if(this->flipped)
        return this->mapToScene(this->leftContRect.center());

    return this->mapToScene(this->rightContRect.center());
}

int Transistor::getPosIndex()
{
    return this->posIndex;
}

QPointF Transistor::getGatePos()
{
    if(this->transistorType.compare("PMOS") == 0)
        return this->mapToScene(-Rules::getRule("PO.W.1a")/2,gateRect.bottom());
    else
        return this->mapToScene(-Rules::getRule("PO.W.1a")/2,gateRect.top());
}

QRectF Transistor::getSourceDiffWithM1Intersection(Metal *m1)
{
    QRectF sourceDiffRect = diffRect;
    sourceDiffRect.setTopLeft(mapToScene(sourceDiffRect.topLeft()));
    sourceDiffRect.setSize(diffRect.size());

    QRectF m1Rect(m1->x(),m1->y(),m1->bottomRight.x(),m1->bottomRight.y());

    if(flipped)
        sourceDiffRect.setX(sourceDiffRect.x() + 27.5);
    else
        sourceDiffRect.setWidth(10.5);

    return sourceDiffRect.intersected(m1Rect);
}

QRectF Transistor::getDrainDiffWithM1Intersection(Metal *m1)
{
    QRectF drainDiffRect = diffRect;
    drainDiffRect.setTopLeft(mapToScene(drainDiffRect.topLeft()));
    drainDiffRect.setSize(diffRect.size());

    QRectF m1Rect(m1->x(),m1->y(),m1->bottomRight.x(),m1->bottomRight.y());

    if(flipped)
        drainDiffRect.setWidth(10.5);
    else
        drainDiffRect.setX(drainDiffRect.x() + 27.5);

    return drainDiffRect.intersected(m1Rect);
}

Metal *Transistor::getGateRect()
{
    Metal *po = new Metal();
    po->metalType = "PO";
    po->net = gateNetName;
    po->bottomRight = QPointF(Rules::getRule("PO.W.1a"),gateRect.height());
    po->setPos(this->pos().x() -(Rules::getRule("PO.W.1a")/2), this->pos().y());

    return po;
}

Metal *Transistor::getDiffRect()
{
    Metal *diff = new Metal();
    diff->metalType = "OD";
    diff->net = gateNetName;
    diff->bottomRight = QPointF(diffRect.width(),diffRect.height());
    diff->setPos(mapToScene(diffRect.topLeft()));

    return diff;
}

QRectF Transistor::boundingRect() const
{
    return QRectF(-((Rules::getRule("PO.W.1a")/2) + Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1")),
                  0,
                  Rules::getRule("PO.W.1a") + (Rules::getRule("CO.E.1") + Rules::getRule("CO.W.1") + Rules::getRule("CO.C.1"))*2,
                  this->w + (Rules::getRule("PO.O.1"))*2);
}

void Transistor::printDiffCifFormat(QTextStream *out)
{
    QPointF bottomLeft = mapToScene(diffRect.bottomLeft());
    QPointF bottomRight = mapToScene(diffRect.bottomRight());
    QPointF topRight = mapToScene(diffRect.topRight());
    QPointF topLeft = mapToScene(diffRect.topLeft());

    QString p;

    p = QString::number(bottomLeft.x()*10) + "," + QString::number(bottomLeft.y()*10);
    p += " " + QString::number(bottomRight.x()*10) + "," + QString::number(bottomRight.y()*10);
    p += " " + QString::number(topRight.x()*10) + "," + QString::number(topRight.y()*10);
    p += " " + QString::number(topLeft.x()*10) + "," + QString::number(topLeft.y()*10) + ";";

    *out <<"P "  + p << endl;
}

void Transistor::printPoCifFormat(QTextStream *out)
{
    QPointF bottomLeft = mapToScene(gateRect.bottomLeft());
    QPointF bottomRight = mapToScene(gateRect.bottomRight());
    QPointF topRight = mapToScene(gateRect.topRight());
    QPointF topLeft = mapToScene(gateRect.topLeft());

    QString p;

    p = QString::number(bottomLeft.x()*10) + "," + QString::number(bottomLeft.y()*10);
    p += " " + QString::number(bottomRight.x()*10) + "," + QString::number(bottomRight.y()*10);
    p += " " + QString::number(topRight.x()*10) + "," + QString::number(topRight.y()*10);
    p += " " + QString::number(topLeft.x()*10) + "," + QString::number(topLeft.y()*10) + ";";

    *out << "P " +  p << endl;
}


void Transistor::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QBrush brush;
    QPen pen;
    QTransform tr;
    tr.scale(1/(*scale),1/(*scale));
    brush.setTransform(tr);

    //DIFF
    brush.setColor(QColor(0,0XCC,0x66));
    brush.setStyle(Qt::Dense6Pattern);
    pen.setColor(QColor(0,0XCC,0x66));
    pen.setWidth(0);
    painter->setBrush(brush);
    painter->setPen(pen);
    painter->drawRect(diffRect);

    //CONT
    brush.setColor(Qt::transparent);
    brush.setStyle(Qt::SolidPattern);
    pen.setColor(QColor(0XFF,0xFF,0));
    //brush.setStyle(Qt::DiagCrossPattern);
    painter->setBrush(brush);
    painter->setPen(pen);

    //M1
    brush.setColor(QColor(0,0,0XFF));
    brush.setStyle(Qt::FDiagPattern);
    pen.setColor(QColor(0,0,0XFF));
    painter->setBrush(brush);
    painter->setPen(pen);

    //GATE
    brush.setColor(QColor(0XFF,0,0));
    brush.setStyle(Qt::BDiagPattern);
    pen.setColor(QColor(0XFF,0,0));
    pen.setWidth(0);
    painter->setBrush(brush);
    painter->setPen(pen);
    painter->drawRect(gateRect);

    if(drawNetNames)
    {
        QFont font;
        font.setPixelSize(3);
        pen.setColor(Qt::white);
        painter->setFont(font);
        painter->setPen(pen);

        if(!this->flipped)
        {
            painter->drawText(this->diffRect,Qt::AlignLeft | Qt::AlignVCenter,this->sourceNetName);
            painter->drawText(this->diffRect,Qt::AlignRight | Qt::AlignVCenter,this->drainNetName);
        }
        else
        {
            painter->drawText(this->diffRect,Qt::AlignLeft | Qt::AlignVCenter,this->drainNetName);
            painter->drawText(this->diffRect,Qt::AlignRight | Qt::AlignVCenter,this->sourceNetName);
        }
        painter->drawText(this->gateRect,Qt::AlignCenter,this->gateNetName);
    }

}


